<?php

namespace app\index\service;

use app\common\model\MemberToken;
use app\index\dao\MemberTokenDao;
use ShidianUtil\Utils\RandUtil;
use think\exception\ValidateException;
use think\facade\Log;

/**
 * 登录令牌
 * Class MemberTokenService
 * @package app\index\service
 */
class MemberTokenService
{

    private MemberTokenDao $tokenDao;

    public function __construct(MemberTokenDao $tokenDao)
    {
        $this->tokenDao = $tokenDao;
    }

    /**
     * 刷新登录token
     * @param $memberId
     * @param $channel
     * @param int $max 允许同时登录的数量
     * @param int $maxTimes
     * @return string
     */
    public function add($memberId, $channel, int $max = 1, int $maxTimes = 3): string
    {
        $params = [
            'memberId' => $memberId,
            'channel' => $channel,
            'token' => RandUtil::token(true),
        ];

        try {
            $record = $this->tokenDao->insertActive($params);

            // 插入成功后，删除其他token
            $count = MemberToken::where('memberId', $memberId)->where('channel', $channel)->count();
            if ($count > $max) {
                // 删除最早的token，直到满足数量要求
                $ids = MemberToken::where('memberId', $memberId)
                    ->where('channel', $channel)
                    ->field(['id'])
                    ->order('id', 'ASC')
                    ->limit($count - $max)
                    ->select()
                    ->column('id');
                if (!empty($ids)) {

                    Log::info('移除过期token' . implode(',', $ids));

                    MemberToken::destroy(fn($query) => $query->whereIn('id', $ids));
                }
            }

            return $params['token'];
        } catch (\Exception $exception) {
            if ($maxTimes <= 0) {
                Log::info('登录失败' . $exception->getMessage());
                throw new ValidateException('登录失败');
            }
            return $this->add($memberId, $channel, $max, $maxTimes - 1);
        }

    }

    /**
     * 退出登录
     * @param $memberId
     * @return void
     */
    public function delete($memberId): void
    {
        MemberToken::destroy(fn($query) => $query->where('memberId', $memberId));
    }
}
